{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "78f7ed49",
   "metadata": {},
   "source": [
    "# Debugging the CW308_STM32F3 Using ChipWhisperer"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9a4094de",
   "metadata": {},
   "source": [
    "## Background\n",
    "\n",
    "When testing software, it can be extremely helpful to view and modify the state of the software while it is running. For programs running on fully featured operating systems (Windows, Mac, Linux, etc.), this can be accomplished by using debugging programs, such as `gdb`. Microcontrollers and FPGAs, on the other hand, require additional hardware to debug. While it is better to use a device dedicated to debugging, beginning with ChipWhisperer 5.6.1, you can use your ChipWhisperer capture board to debug target devices. This is done over SWD/JTAG, which most devices support. To see if your target supports JTAG/SWD, you should check the reference manual/datasheet for its microcontroller.\n",
    "\n",
    "This demo will run will show you how to set your hardware up for debugging, how to set the software up for debugging, and finally how to program and debug an STM32F3. In addition to this demo, you may want to skip through and have open our [debugging documentation](https://chipwhisperer.readthedocs.io/en/latest/debugging.html)."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6e369ca0",
   "metadata": {},
   "source": [
    "## Checking for ChipWhisperer Support\n",
    "\n",
    "This demo requires ChipWhisperer 5.6.1. In addition, you must have firmware from this version of ChipWhisperer or newer running on your device. Run the following line to check for support:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cf26e135",
   "metadata": {},
   "outputs": [],
   "source": [
    "import chipwhisperer as cw\n",
    "if cw.__version__ < '5.6.1':\n",
    "    print(\"MPSSE not supported.\")\n",
    "else:\n",
    "    scope = cw.scope()\n",
    "    if scope.check_feature(\"MPSSE\"):\n",
    "        print(\"MPSSE supported!\")\n",
    "    else:\n",
    "        print(\"MPSSE not supported.\")\n",
    "    scope.dis()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "92827159",
   "metadata": {},
   "source": [
    "## Software Prerequisites\n",
    "\n",
    "In addition to ChipWhisperer, you will need the following software:\n",
    "\n",
    "1. OpenOCD, available at https://openocd.org/pages/getting-openocd.html. It's recommended that you download an OpenOCD binary or built it yourself, rather than getting it through a package manager, as the package manager will usually install an old version of OpenOCD\n",
    "1. GDB for your device of choice (`arm-none-eabi-gdb`, in our case). This is typically included with the compiler you use to build firmware for your target.\n",
    "\n",
    "Ensure both openocd and gdb are available on your path:\n",
    "\n",
    "* Windows: https://www.computerhope.com/issues/ch000549.htm (set in user variables)\n",
    "* Mac/Linux: https://superuser.com/questions/488173/how-can-i-edit-the-path-on-linux\n",
    "\n",
    "Once you've got those installed, quit jupyter and reopen it in a new terminal window so that your path updates. Make sure you're able to access both of these programs:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2fdb484b",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash\n",
    "arm-none-eabi-gdb --version"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "75401086",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash\n",
    "openocd --version"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ece19eda",
   "metadata": {},
   "source": [
    "## Hardware Setup\n",
    "\n",
    "### ChipWhisperer-Lite, Pro, Nano, or Husky with CW308T_STM32F3\n",
    "\n",
    "1. Connect your ChipWhisperer capture board to your PC\n",
    "1. Connect your capture board and CW308 via the CW 20-pin connector\n",
    "1. Use jumper wires to connect the following pins on the CW308:\n",
    "    1. J5 Pin 12 (SCK)  -> J8 Pin 6 (J_TCK)\n",
    "    1. J5 Pin 18 (PDID) -> J8 Pin 5 (J_TMS)\n",
    "    1. J5 Pin 13 (MISO) -> J8 Pin 4 (J_TDO)\n",
    "    1. J5 Pin 14 (MOSI) -> J8 Pin 3 (J_TDI)\n",
    "    \n",
    "<img src=\"img/MPSSE_con_1x.jpg\" alt=\"MPSSE-DIO\" width=600>\n",
    "    \n",
    "### ChipWhisperer-Husky with CW308T_STM32F3 using 20-pin DIO Header\n",
    "\n",
    "1. Connect your ChipWhisperer capture board to your PC\n",
    "1. Connect your capture board and CW308 via the CW 20-pin connector\n",
    "1. Connect the 20-pin DIO header to J6 on the CW308. Ensure the keyed part of the connector is facing away from the board\n",
    "\n",
    "<img src=\"img/MPSSE_con_3.jpg\" alt=\"MPSSE-DIO\" width=600>\n",
    "\n",
    "### ChipWhisperer-Lite, Pro, Nano, or Husky with CW312T_STM32F3\n",
    "\n",
    "Coming soon!"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "613af32e",
   "metadata": {},
   "source": [
    "## Software Setup\n",
    "\n",
    "### Lite, Pro, Nano, or Husky (non DIO) Setup\n",
    "\n",
    "All you need to do to enable MPSSE is connect to your scope and run `scope.enable_MPSSE(1)` (we'll also record the CW's USB PID for later usage):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "03ac9803",
   "metadata": {},
   "outputs": [],
   "source": [
    "import chipwhisperer as cw\n",
    "scope = cw.scope()\n",
    "PID = hex(scope._getNAEUSB().usbtx.device.getProductID())\n",
    "scope.enable_MPSSE(1)\n",
    "scope.dis()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4a15fb35",
   "metadata": {},
   "source": [
    "###  Husky DIO Setup\n",
    "\n",
    "Alternatively, if you want to use the ChipWhisperer-Husky's 20-pin DIO header, enable that before running `scope.enable_MPSSE(1)`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7d3f8017",
   "metadata": {},
   "outputs": [],
   "source": [
    "import chipwhisperer as cw\n",
    "scope = cw.scope()\n",
    "PID = hex(scope._getNAEUSB().usbtx.device.getProductID())\n",
    "scope.enable_MPSSE(1, husky_userio='jtag') # or husky_userio='swd'"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "36d62626",
   "metadata": {},
   "source": [
    "With that done, we can now debug our target. Note that `scope.enable_MPSSE(1)` will disconnect your target in Python, meaning you'll have to reconnect to interact via the API. On Windows, only one process at a time can access a USB device, meaning if you reconnect in Python, you won't be able to connect in OpenOCD and vice versa.\n",
    "\n",
    "We'll start by building and uploading some firmware to the target:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e79064fb",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash -s \"$PID\"\n",
    "\n",
    "# build firmware\n",
    "cd ../../firmware/mcu/simpleserial-aes\n",
    "make PLATFORM=CW308_STM32F3 CRYPTO_TARGET=TINYAES128C SS_VER=SS_VER_1_1 -j\n",
    "\n",
    "# upload firmware via JTAG\n",
    "openocd -f ../../../../openocd/cw_openocd.cfg -c \"transport select jtag\" -c \"ftdi vid_pid 0x2b3e $1\" -f \"target/stm32f3x.cfg\" -c \"init\" -c \"targets\" -c \"halt\" -c \"flash write_image erase simpleserial-aes-CW308_STM32F3.elf\" -c \"flash verify_image simpleserial-aes-CW308_STM32F3.elf\" -c \"reset run\" -c \"shutdown\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "73ebe432",
   "metadata": {},
   "source": [
    "If you don't see any errors, then congratulations: You've now used JTAG to upload code onto your target! Next, let's do a little debugging instead. We'll begin by running openocd again, with some different commands:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8fcf7725",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%bash -s \"$PID\"\n",
    "\n",
    "# build firmware\n",
    "cd ../../firmware/mcu/simpleserial-aes\n",
    "\n",
    "openocd -f ../../../../openocd/cw_openocd.cfg -c \"transport select jtag\" -c \"ftdi vid_pid 0x2b3e $1\" -f \"target/stm32f3x.cfg\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f4699a28",
   "metadata": {},
   "source": [
    "**NOTE: The above command will continuously run until you restart this jupyter notebook**\n",
    "\n",
    "If we want to do some actual debugging, we'll need an interactive terminal. Any terminal with access to the correct gdb and openocd will work, but we'll use Jupyter's terminal here, as it already has everything setup:\n",
    "\n",
    "![asdf](img/jupyter_terminal.png)\n",
    "\n",
    "To start debugging, run the following commands in that terminal (you may need to adjust the paths if you don't start in the jupyter folder):\n",
    "\n",
    "```bash\n",
    "# try cd firmware/mcu/simpleserial-aes if the command below doesn't work\n",
    "cd ../firmware/mcu/simpleserial-aes \n",
    "arm-none-eabi-gdb simpleserial-aes-CW308_STM32F3.elf -ex \"target extended-remote localhost:3333\" -ex \"monitor reset halt\" -ex \"load\"\n",
    "```\n",
    "\n",
    "You should now have an active gdb session up and running:\n",
    "\n",
    "![](img/gdb_startup.png)\n",
    "\n",
    "We won't do a full gdb tutorial, but here's some basic commands to get you up and running:\n",
    "quit\n",
    "* `help` - prints a useful help screen\n",
    "* `bt` - prints all stack frames (i.e. all the functions from `main()` down to your current position)\n",
    "* `s` - step program until it reaches the next source line (moves into function)\n",
    "* `n` - step program, proceeding through subroutine calls (moves above functions)\n",
    "* `l` - list source lines around current location\n",
    "\n",
    "**Warning: the start and run commands may not properly restart the firmware. You can restart from the beginning of your code by running `load` followed by `s`**\n",
    "\n",
    "![](img/using_gdb.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "61bd6cf7",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
